/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Negocio;

import BaseDatos.GestorBD;
import TablasAuxiliares.TATiposBien;
import Util.GestorErrores;
import Util.Varios;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.Vector;

/**
 * Esta clase modela y gestiona el proceso de  compra de un bien por un cliente mediante un préstamo.
 * Este proceso genera una solicitud de préstamo (en primer lugar) y después, si es aprobada, dará
 * lugar a un préstamo.
 * Las 2 clases solicitud de préstamo y Préstamo derivan de esta clase. La única diferencia entre
 * ambas es que en una solicitud de préstamo la variable Concedido = false, y cuando se convierte en
 * un préstamo Concedido = true.
 *
 * @author Javi
 */
public class DatosPrestamo implements ObjetoDatos{
    //Nombre de la tabla de la Base de Datos (esta entidad no tiene asociada directamente una tabla)
    private String _sNombreTabla = "";
    //Descripción de la tabla de la Base de Datos
    private String _sDescripTabla = "Datos del proceso de compra mediante un préstamo";
    //Condición where
    private String sCondWhere = "";

    //Objetos de los que se compone el objeto DatosPrestamo
    private Cliente _oCliente = new Cliente();
    private Compra _oCompra = new Compra();
    private Bien _oBien = new Bien();
    private TATiposBien _oTipoBien = new TATiposBien();

    //Atributos de la entidad lógica DatosPrestamo
    private int _iIdCliente;
    private int _iIdBien;
    private Date _dFecha;
    //Nos permite distinguir cuando es un préstamo formalizado o una mera solicitud de préstamo
    private boolean _bConcedido;

    /*
     * Recupera todo el contenido de la tabla y lo devuelvo en 2 vectores. Uno con los nombres de los campos y
     * otro vector de vectores con los datos propiamente dichos (cada tupla de datos en un vector). El orden de los
     * campos de la fila es el mismo que el de los nombres de los campos.
     */
    public boolean selectAll ( Vector columnIdentifiers, Vector dataVector){
        String sCondicion = "";
        //Añado una condición ADICIONAL para distinguir entre una Solicitud de Préstamo y un Préstamo
        if (this._bConcedido)
            sCondicion = " AND Concedido = 1 ";
        else
            sCondicion = " AND Concedido = 0 ";
        //Si hay alguna condición se añade a la sentencia
        if (this.sCondWhere.compareTo("") != 0)
            sCondicion = sCondicion + " AND " + this.sCondWhere;
        //Recupero los nombres de las tablas implicadas
        String C = this._oCompra.getsNombreTabla();
        String CDP = this._oCliente.getoClienteDatPers().getsNombreTabla();
        String B = this._oBien.getsNombreTabla();
        String TB = this._oTipoBien.getsNombreTabla();
        //Monto la SQL
        String sSQL = "SELECT " + CDP + ".idCliente, " + CDP + ".TipoDocumento, " + CDP + ".NumDocumento, " +
                CDP + ".Nombre, " + CDP + ".Apellidos, " + C + ".fechaCompra, " + 
                B + ".IdBien, " +
                B + ".Importe, " + TB + ".Descripcion," + C + ".Autorizada, " + C + ".EstudioMorosidad " +
                " FROM " + CDP + "," + C + "," + B + "," + TB +
                " WHERE " + CDP + ".idCliente = " + C + ".idCliente AND " +
                B + ".idbien = " + C + ".idbien AND " +
                B + ".Tipo = " + TB + ".Codigo " + sCondicion +
                " ORDER BY " + CDP + ".Apellidos," + CDP + ".Nombre, " + TB + ".Descripcion";
        try {
            Statement st = GestorBD.getInstancia().getConexion().createStatement();
            ResultSet rs = st.executeQuery(sSQL);
            ResultSetMetaData metaDatos = rs.getMetaData();
            // Se obtiene el número de columnas.
            int numeroColumnas = metaDatos.getColumnCount();
            // Se obtiene cada una de las etiquetas para cada columna
            for (int i = 0; i < numeroColumnas; i++){
               // Nuevamente, para ResultSetMetaData la primera columna es la 1.
               columnIdentifiers.addElement( metaDatos.getColumnLabel(i + 1) );
            }

            while (rs.next()) {
                // Se crea un vector que será cada fila de la tabla.
                Vector fila = new Vector (numeroColumnas);

                // Se rellena cada posición del vector con una de las columnas de la tabla en base de datos.
                for (int i = 0; i < numeroColumnas; i++)
                    fila.addElement ( rs.getObject(i+1) ); // El primer indice en rs es el 1, no el cero, por eso se suma 1.

                // Se añade al modelo la fila completa.
                dataVector.addElement( fila );
            }
            rs.close();
            st.close();
            return true;
        }catch (SQLException e1){
            GestorErrores.getInstancia().getvErrores().add ( e1.getMessage() );
        }catch(Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /*
     * Inserta un registro en la entidad
     *  - Inserta un registro en la tabla de bienes
     *  - Inserta un registro en la tabla de compras
     */
    public boolean insert ( ){
        if ( !validar () )
            return false;
        //Actualizo el idCliente en la clase compra
        this._oCompra.setiIdCliente( this._iIdCliente );
        //INICIAR TRANSACCION
        GestorBD.getInstancia().abrirTransaccion();
        //Inserto primero en la tabla de bienes principal
        boolean bResultado = this._oBien.insert();
        //Actualizo las demás clases con el IDBIEN generado AUTOMATICAMENTE
        this._iIdBien = this._oBien.getiIdBien();   //Actualizo en la clase principal
        this._oCompra.setiIdBien( this._oBien.getiIdBien() );   //Actualizo en la clase compra
        //Inserto en el resto de las tablas.
        bResultado = bResultado & this._oCompra.insert();
        //CERRAR TRANSACCION
        GestorBD.getInstancia().cerrarTransaccion(bResultado);
        return bResultado;
    }


    /*
     * Actualiza un registro en la entidad
     *  - Actualiza un registro en la tabla de bienes
     *  - Actualiza un registro en la tabla de compras
     */
    public boolean update (){
        if ( !validar () )
            return false;
        //INICIAR TRANSACCION
        GestorBD.getInstancia().abrirTransaccion();
        //Actualizo primero en la TABLA DE Bienes
        boolean bResultado = this._oBien.update();
        //Actualizo despues en la tabla de Compras
        //Controlo si se ha seleccionado otro idcliente
        if ( this._iIdCliente != this._oCompra.getiIdCliente() ){
            //Borro el registro asociado al cliente antiguo
            bResultado = bResultado & this._oCompra.delete();
            //Actualizo el campo IdCliente con el nuevo
            this._oCompra.setiIdCliente(this._iIdCliente);
            //E inserto el nuevo registro asociado al nuevo cliente
            bResultado = bResultado & this._oCompra.insert();
        }else
            bResultado = bResultado & this._oCompra.update();
        //CERRAR TRANSACCION
        GestorBD.getInstancia().cerrarTransaccion(bResultado);
        return bResultado;
    }

    /*
     * Borra un registro de la Entidad
     *  - Borra un registro de la tabla de Bienes
     *  - Borra un registro de la tabla de Compras
     */
    public boolean delete (){
        //INICIAR TRANSACCION
        GestorBD.getInstancia().abrirTransaccion();
        //Borro primero en la tabla de compras
        boolean bResultado = this._oCompra.delete();
        //Borro despues en la tabla de bienes
        bResultado = bResultado & this._oBien.delete();
        //CERRAR TRANSACCION
        GestorBD.getInstancia().cerrarTransaccion(bResultado);
        return bResultado;
    }

    /*
     * Valida los datos de la clase antes de hacer una inserción/actualización.
     * Se informa de los errores que se produzcan mediante un vector de String.
     */
    public boolean validar (){
        boolean bOK = true;
        if ( this._iIdCliente == 0 ){
            GestorErrores.getInstancia().getvErrores().add ("Es obligatorio seleccionar un cliente");
            bOK = false;
        }

        return ( bOK & this._oBien.validar() &
            this._oCompra.validar() );
    }

    /*
     * Carga en la clase SOLO los atributos que conforman la clave de la entidad a partir de 2 vectores,
     * uno con los nombres de los campos
     * y otro con los valores de los mismos.
     */
    public void vectorJTableAClavesClase ( Vector columnIdentifiers, Vector dataRow ){
        this.inicializa();
        int iIndice = Varios.getPosCadena(columnIdentifiers, "IdCliente");
        this._iIdCliente = Integer.parseInt( dataRow.get(iIndice).toString() );
        iIndice = Varios.getPosCadena(columnIdentifiers, "IdBien");
        this._iIdBien = Integer.parseInt( dataRow.get(iIndice).toString() );
        iIndice = Varios.getPosCadena(columnIdentifiers, "fechaCompra");
        this._dFecha = Varios.stringToDate( dataRow.get(iIndice).toString() );

    }

    /*
     * Devuelve un vector cargado con los atributos de la clase para mostrar en el JTable del panel.
     * El orden de los atributos es el indicado
     * en el vector con los nombres de los campos.
     */
    public Vector claseAVectorJTable ( Vector columnIdentifiers ){
        Vector resul = new Vector ();
//        for (int i=0; i < columnIdentifiers.size(); i++){
//            if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("IdCliente") == 0 )
//                resul.add( this._iIdCliente );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("TipoDocumento") == 0 )
//                resul.add( this._oCliente.getoClienteDatPers().getsTipoDocumento() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("NumDocumento") == 0 )
//                resul.add( this._oCliente.getoClienteDatPers().getsNumDocumento() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("Nombre") == 0 )
//                resul.add( this._oCliente.getoClienteDatPers().getsNombre() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("Apellidos") == 0 )
//                resul.add( this._oCliente.getoClienteDatPers().getsApellidos() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("FechaCompra") == 0 )
//                resul.add( this._oCompra.getdFechaCompra() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("IdBien") == 0 )
//                resul.add( this._iIdBien );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("Importe") == 0 )
//                resul.add( this._oBien.getiImporte() );
//            else if ( ((String) columnIdentifiers.get(i)).compareToIgnoreCase("Descripcion") == 0 )
//                resul.add( this._bExtranjero );
//        }
        return resul;
    }

    /*
     * Este método recupera de la tabla un registro cuya clave primaria están cargados en los
     atributos de la clase correspondientes a la clave. Se recuperan los campos del registro y
     se carga el resto de los atributos de la clase.
     *  - Se recupera toda la información de un cliente (los datos personales)
     *  - Se recupera un registro de la tabla bienes
     *  - Se recupera un registro de la tabla compras
     */
    public void recupera (){
        //Asigno el id de cliente y la fecha de solicitud para recuperar los datos del cliente
        //a la fecha de la solicitud/préstamo
        this._oCliente.setiIdCliente(this._iIdCliente);
        this._oCliente.setdFecha(this._dFecha);
        this._oCliente.recupera();
        //Asigno el id de bien para recuperar el bien
        this._oBien.setiIdBien(this.getiIdBien());
        this._oBien.recupera();
        //Asigno el id de cliente y de cliente para recuperar la compra
        this._oCompra.setiIdCliente(this.getiIdCliente());
        this._oCompra.setiIdBien(this.getiIdBien());
        this._oCompra.recupera();
    }

    public void inicializa (){
        this._iIdCliente = 0;
        this._iIdBien = 0;
        this._dFecha = new Date();  //la fecha de hoy
        this._oCliente.inicializa();
        this._oBien.inicializa();
        this._oCompra.inicializa();
        //Los atributos que son distintos en la Solicitud de Préstamo y en el PRéstamo se
        //inicializan en las clases derivadas correspondientes.
    }

    public int getiIdCliente() {
        return _iIdCliente;
    }

    public void setiIdCliente(int _iIdCliente) {
        this._iIdCliente = _iIdCliente;
    }

    public String getsNombreTabla() {
        return _sNombreTabla;
    }

    public void setsNombreTabla(String _sNombreTabla) {
        this._sNombreTabla = _sNombreTabla;
    }

    public String getsDescripTabla() {
        return _sDescripTabla;
    }

    public void setsDescripTabla(String _sDescripTabla) {
        this._sDescripTabla = _sDescripTabla;
    }

    public int getiIdBien() {
        return _iIdBien;
    }

    public void setiIdBien(int _iIdBien) {
        this._iIdBien = _iIdBien;
    }

    public Bien getoBien() {
        return _oBien;
    }

    public void setoBien(Bien _oBien) {
        this._oBien = _oBien;
    }

    public Cliente getoCliente() {
        return _oCliente;
    }

    public void setoCliente(Cliente _oCliente) {
        this._oCliente = _oCliente;
    }

    public Compra getoCompra() {
        return _oCompra;
    }

    public void setoCompra(Compra _oCompra) {
        this._oCompra = _oCompra;
    }

    public String getsCondWhere() {
        return sCondWhere;
    }

    public void setsCondWhere(String sCondWhere) {
        this.sCondWhere = sCondWhere;
    }

    public boolean isbConcedido() {
        return this._bConcedido;
    }

    public void setbConcedido(boolean _bCasoReal) {
        this._bConcedido = _bCasoReal;
    }

    public TATiposBien getoTipoBien() {
        return _oTipoBien;
    }

    public void setoTipoBien(TATiposBien _oTipoBien) {
        this._oTipoBien = _oTipoBien;
    }

    public Date getdFecha() {
        return _dFecha;
    }

    public void setdFecha(Date _dFecha) {
        this._dFecha = _dFecha;
    }

}
